﻿using DDD.Application;
using DDD.Core;
using DDD.EFCore;
using DDD.EFCore.Shared;
using FluentValidation;
using FluentValidation.AspNetCore;
using GoodsModule.Application.IntegrationEventsHandler;
using GoodsModule.Application.Queries;
using GoodsModule.Infrastructure;
using GoodsModule.Infrastructure.Queries;
using GoodsModule.Infrastructure.Repositories;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using OrderModule.IntegrationEvents;
using System.Reflection;

namespace GoodsModule.Application
{
    public static class ServiceCollectionExtensions
    {
        public static IServiceCollection AddGoodsModule(this IServiceCollection services, IConfiguration configuration, Assembly assembly)
        {
            Console.WriteLine("Assembly.GetCallingAssembly().FullName:{0}", Assembly.GetCallingAssembly().FullName);
            Console.WriteLine("Assembly.GetEntryAssembly().FullName:{0}", Assembly.GetEntryAssembly()?.FullName);
            Console.WriteLine("Assembly.GetExecutingAssembly().FullName:{0}", Assembly.GetExecutingAssembly().FullName);

            var moduleName = Assembly.GetExecutingAssembly().FullName?.Split(", ")[0].Split(".")[0];
            Console.WriteLine("moduleName:{0}", moduleName);
            if (moduleName != null && configuration.GetSection(moduleName).Exists())
            {
                configuration = configuration.GetSection(moduleName);
            }

            services.AddAutoMapper(typeof(AutoMapperProfile));
            services.AddFluentValidationAutoValidation();
            services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly());

            //services.TryAddScoped<IPublisherTransactionHandler, MySqlPublisherTransactionHandler>();
            //services.TryAddTransient<IMediator, Mediator>();

            services.AddDbContext<GoodsModuleDbContext>(o => o.UseMySql(configuration.GetConnectionString("MySql")));

            services.AddMediatR(cfg =>
            {
                cfg.Lifetime = ServiceLifetime.Scoped;
                cfg.RegisterServicesFromAssemblies(Assembly.GetExecutingAssembly());
                cfg.AddOpenBehavior(typeof(GoodsModuleCommandUnitOfWorkBehavior<,>));
            });
            services.AddCap(o =>
            {
                o.UseEntityFramework<GoodsModuleDbContext>();
                //o.UseMySql(configuration.GetConnectionString("MySql"));
                o.UseRabbitMQ(p => configuration.GetSection("RabbitMQ").Bind(p));
                o.UseDashboard();
            });

            //TODO: 用反射注册
            services.AddScoped<GoodsRepository>();
            services.AddScoped<GoodsCategoryRepository>();
            services.AddScoped<GoodsQuery>();
            services.AddScoped<GoodsCategoryQuery>();
            //services.AddRepositories(typeof(GoodsRepository).Assembly, typeof(GoodsCategoryRepository).Assembly);
            services.AddTransient(typeof(GoodsCreatedIntegrationEventHandler));
            services.AddTransient(typeof(OrderCreatedIntegrationEventHandler));


            //services.AddUnitOfWork<GoodsModuleDbContext>();
            services.AddScoped<IUnitOfWork>(p => p.GetRequiredService<GoodsModuleDbContext>());
            services.AddScoped<ITransaction>(p => p.GetRequiredService<GoodsModuleDbContext>( ));

            return services;
        }

        //private static IServiceCollection AddUnitOfWork<TDbContext>(this IServiceCollection services)
        //    where TDbContext : IUnitOfWork, ITransaction
        //{
        //    services.AddScoped<IUnitOfWork<TDbContext>>(p => p.GetRequiredService<TDbContext>());
        //    services.AddScoped<ITransaction>(p => p.GetRequiredService<TDbContext>());
        //    return services;
        //}

        //private static IServiceCollection AddRepositories(this IServiceCollection services, params Assembly[] assemblies)
        //{
        //    var types = assemblies.SelectMany(assembly => assembly.GetTypes());

        //    foreach (var repositoryType in types.Where(x =>
        //                 !x.IsGenericType && !x.IsAbstract && x.BaseType != null && x.BaseType.IsGenericType &&
        //                 (x.BaseType.GetGenericTypeDefinition() == typeof(Repository<,,>)
        //                  || x.BaseType.GetGenericTypeDefinition() == typeof(Repository<,>))))
        //    {
        //        services.TryAddScoped(repositoryType);
        //        var repositoryInterfaceType = Array.Find(repositoryType.GetInterfaces(),
        //            x => !x.IsGenericType && Array.Exists(x.GetInterfaces(),
        //                i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IRepository<>)));

        //        if (repositoryInterfaceType == null)
        //            continue;
        //        services.TryAddScoped(repositoryInterfaceType, p => p.GetRequiredService(repositoryType));
        //    }

        //    return services;
        //}

    }
}
